.syntax xforth "./meta";
.initialize .var(*stacklen) .var(*entry) .prototype(comment);

line = .token .neq(10) *.neq(10) .deftoken;
id = .token .id .adjtoken \ *(.eq('.') .id) / .deftoken;
mathop = '+' | '-' | '*' | '/';
number = .token .number .adjtoken *(mathop .number) .deftoken;

entry = 'entry' id .set(entry);
stack = 'retstack' number .set(stacklen);
configs = ^stack ^entry;

prelude = 'prelude' {'; user prologue:\n'}
  *('endprelude' {nl} .success | comment | line {$ nl});

includes = 'includes'
  *('endincludes' {nl} .success | .string {'include '$ nl});

word = 'word' id {$ ':' nl '  dd _enter_routine' nl}
  *('endword' {'  dd _leave_routine' nl} .success
   |'literal' {'  dd _literal' nl} (.number|id) {'  dd '$ nl}
   |(.number|id) {'  dd '$ nl} );

code = 'code' id {$ ':' nl '  dd _enter_native' nl}
  *('endcode' {'  jmp _next_routine' nl} .success
   | line {'  '$ nl});

comment = '/' line | ';' line;

fasm_bootstrap = {"format elf executable 3
entry _start
include './symbols.inc'
include './structs.inc'
include './ithread.inc'\n\n"};

fasm_start = {'segment writeable
  return_stack_top dd ?
  stack_top dd ?
segment executable
_start:
  cld
  mov ebp, esp
  sub esp, '} .ifte(stacklen,"2*1024*1024") {'
  mov [stack_top], esp
  mov [return_stack_top], ebp
  mov esi, .forth_boot
  jmp _next
.forth_boot:
  dd _enter_routine
  dd '} .ifte(entry,"main") {'
  dd _halt

; user code:\n'};

program =
  *comment (configs | .e)
  fasm_bootstrap
  *comment (includes | .e)
  *comment (prelude | .e)
  fasm_start
  .expect('Comentário ou código')
  (comment | word | code) *(comment | word | code);

.end program;
